import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';

typedef TransformValue<T> = T? Function(dynamic data);

/// 解析映射key
class MappingKey {
  static const code = "code";
  static const description = "message";
  static const data = "data";
  static const target = "target";
  static const transformer = "transformer";
}

/// 响应结果
class ResponseResult<T> {
  /// 数据
  T? data;

  /// 字典
  Map<String, dynamic>? dataMap;

  /// 数组
  List? dataList;

  /// 数据流
  Stream? stream;

  /// 异常
  NetworkException? exception;

  ResponseResult(
      {this.data, this.dataMap, this.dataList, this.stream, this.exception});

  /// 请求成功
  bool get isSuccess => exception == null;

  static ResponseResult<T> copyWith<T>(ResponseResult result) {
    return ResponseResult<T>(
      data: result.data,
      dataMap: result.dataMap,
      dataList: result.dataList,
      stream: result.stream,
      exception: result.exception,
    );
  }

  @override
  String toString() {
    return "ResponseResult{data: $data, dataMap: $dataMap, dataList: $dataList, stream: $stream, exception: $exception}";
  }
}

/// 异常
class NetworkException implements Exception {
  /// 错误码
  final String code;

  /// 错误信息
  final String? message;

  /// 数据
  dynamic data;

  NetworkException({
    required this.code,
    this.message,
    this.data,
  });

  @override
  String toString() =>
      'NetworkException(code: $code, message: $message, data: $data)';

  NetworkException.system()
      : code = "error",
        message = "Network Error";

  NetworkException.noNet()
      : code = "no_net_work",
        message = "No Network Connection";

  NetworkException copyWith({
    String? code,
    ValueGetter<String?>? message,
    dynamic data,
  }) {
    return NetworkException(
      code: code ?? this.code,
      message: message != null ? message() : this.message,
      data: data ?? this.data,
    );
  }

  Map<String, dynamic> toMap() {
    return {
      'code': code,
      'message': message,
      'data': data,
    };
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;

    return other is NetworkException &&
        other.code == code &&
        other.message == message;
  }

  @override
  int get hashCode => code.hashCode ^ message.hashCode;
}
